﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using nRoute.ViewServices;
using System.Windows.Threading;

namespace nRoute.Samples.OfficerXcel.ViewServices.Controls
{
    [MapViewService(typeof(IInteractiveNotificaitonViewService), Lifetime = ViewServiceLifetime.DiscoveredInstance)]
    public partial class HeaderNotification
        : UserControl, IInteractiveNotificaitonViewService
    {
        private const string VIEWSERVICE_NAME = "DefaultHeaderNotificationViewService";
        private const string HIDDEN_STATENAME = "HiddenState";
        private const string VISIBLE_STATENAME = "VisibleState";
        private readonly static TimeSpan TRANSITION_TIMEOUT = TimeSpan.FromMilliseconds(600);

        private readonly Object _lock = new Object();
        private readonly DispatcherTimer _stateTimer;
        private readonly Queue<InteractiveMessage> _messages;
        private InteractiveMessage _currentMessage;

        public HeaderNotification()
        {
            InitializeComponent();

            // and we register, note_ we are not providing for unregistering the view service
            //ViewServiceLocator.RegisterViewServiceInstance<IInteractiveNotificaitonViewService>(VIEWSERVICE_NAME, this);

            // set up
            _messages = new Queue<InteractiveMessage>();
            _stateTimer = new DispatcherTimer();
            _stateTimer.Interval = TRANSITION_TIMEOUT;
            _stateTimer.Tick += new EventHandler(StateTimer_Tick);

        }

#region IInteractiveNotificationViewService Members

        public void ShowNotification(string notification, Action notificationCallback)
        {
            // basic checks
            if (string.IsNullOrEmpty(notification)) throw new ArgumentNullException("notification");

            // show or enque message
            lock (_lock)
            {
                // if no items are queued then show the message, else enque
                var _message = new InteractiveMessage() { Message = notification, Callback = notificationCallback};
                if (_messages.Count == 0 && _currentMessage == null)
                {
                    ShowMessage(_message);
                }
                else
                {
                    _messages.Enqueue(_message);
                }
            }
        }

#endregion

#region Event Handlers

        void StateTimer_Tick(object sender, EventArgs e)
        {
            _stateTimer.Stop();
            ProcessQueue();
        }

        void CloseHeader_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            // basic check
            if (_stateTimer.IsEnabled) return;
            
            // we stop the timers and start transitioning
            VisualStateManager.GoToState(this, HIDDEN_STATENAME, true);

            // and transiation
            _stateTimer.Start();
        }

        void Header_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            // basic check
            if (_stateTimer.IsEnabled) return;

            // we stop the timers and start transitioning
            VisualStateManager.GoToState(this, HIDDEN_STATENAME, true);

            // and transiation
            _stateTimer.Start();

            // if the user provider us with a callback, we call it
            if (_currentMessage != null &&_currentMessage.Callback != null) 
                _currentMessage.Callback();
        }

#endregion

#region Helpers

        void ProcessQueue()
        {
            lock (_lock)
            {
                if (_messages.Count == 0)
                {
                    _currentMessage = null;
                }
                else
                {
                    ShowMessage(_messages.Dequeue());
                }
            }
        }

        void ShowMessage(InteractiveMessage message)
        {
            this.HeaderText.Text = message.Message;
            VisualStateManager.GoToState(this, VISIBLE_STATENAME, true);
            _currentMessage = message;
        }

#endregion

#region Internal Class

        class InteractiveMessage
        {
            
            public string Message {get; set; }
            
            public Action Callback {get; set; }

        }

#endregion

    }
}
